/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.osgi.tutorial.deployer;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;

/**
 * See the BundleDeployerActivator class
 * @author Filippo Diotalevi filippo.diotalevi at gmail.com
 *
 */
public class DeployerThread implements Runnable {
	
	boolean active = false;
	
	File bundleFolder;
	BundleContext context; 

	public void run() 
	{
		active = initialCheck();
		if (!active)
			System.out.println("Deployer bundle didn't passed the initial check... deployer not starting");
		
		while (active) 
		{
			try {
				doWork();
			} catch (BundleException e1) {
				System.out.println("DeployerThread has raised an exception");
				e1.printStackTrace();
			}
			try {
				Thread.sleep(3000l);
			} catch (InterruptedException e) {
				active = false;
			}
		}
	}

	private boolean initialCheck() {		
		return (bundleFolder!=null) && bundleFolder.exists() && bundleFolder.isDirectory() && (context != null);
	}

	private void doWork() throws BundleException {
		List<Bundle> check = new ArrayList<Bundle>(Arrays.asList(context.getBundles()));
		Collections.copy(check, Arrays.asList(context.getBundles()));		
		
		for (File file : bundleFolder.listFiles()) 
		{
			if (isAJar(file)) {
				Bundle bundle = findAssociatedBundle(file);
				
				if (bundle == null)
				{
					installBundleFile(file);
				}
				else
				{
					check.remove(bundle);
					
					if (file.lastModified() > bundle.getLastModified()) 
					{
						updateBundle(bundle);
					}
				}
			}
		}
		
		if (check.size() > 1)//ignoring the System bundle, ID=0
		{
			for (Bundle bundle : check) 
			{
				if (bundle.getBundleId() > 0)
				{
					removeBundle(bundle);
				}
			}
		}
	}

	private void updateBundle(Bundle bundle) throws BundleException {
		System.out.println("-----------------");
		System.out.println("Bundle updated found: "+bundle.getSymbolicName());
		bundle.update();
		System.out.println("Bundle updated");
	}

	private void installBundleFile(File file) throws BundleException {
		System.out.println("-----------------");
		System.out.println("New bundle found... ");
		Bundle newBundle = context.installBundle(getFilePath(file));
		System.out.println("Installed bundle ID:"+newBundle.getBundleId()+" - "+newBundle.getSymbolicName());					
		newBundle.start();
		System.out.println("Bundle started");
	}

	private void removeBundle(Bundle bundle) throws BundleException {
		System.out.println("-----------------");
		System.out.println("Bundle "+bundle.getSymbolicName()+" doesn't have jar anymore");
		bundle.uninstall();
		System.out.println("Bundle uninstalled");
	}

	/**
	 * Find the installed Bundle associated with the specified jar file
	 * @param file
	 * @return
	 */
	private Bundle findAssociatedBundle(File file) {
		for (Bundle bundle : context.getBundles()) {
			if (bundle.getLocation().equals(getFilePath(file)))
				return bundle;
		}
		return null;
	}

	/**
	 * Calculate the file path of a file, according to felix/osgi notation
	 */
	private String getFilePath(File file) {
		return "file:bundle/"+file.getName();
	}

	private boolean isAJar(File file) {
		return file.isFile() && file.getName().endsWith(".jar");
	}

}
